<?php

/**
 * Created by PhpStorm.
 * Author: ls
 * Time: 2023/8/28 9:22
 * Desc: 微信接口服务
 */

class MiniAppService
{
    private $domain = 'https://api.weixin.qq.com';

    // 小程序app_id
    private $app_id;

    // 小程序app_secret
    private $app_secret;

    // 微信支付商户号
    private $mch_id;

    // access_token
    private $access_token;

    // 证书路径
    private $cert_path;

    // 私钥路径
    private $key_path;

    // token请求地址
    private $token_url = '/cgi-bin/token';

    // 请求路径
    private $path;

    // 请求状态码
    private $request_code;

    // 状态码
    private $error_code = null;

    // 错误信息
    private $error_message = '';

    // 返回内容
    private $content;

    /**
     * 请求参数
     * @var array|mixed
     */
    private $options;

    public function __construct()
    {
        // 默认使用系统配置的微信参数
        $config_params    = [
            'cfg_global_client_appkey', // 小程序 app_id
            'cfg_global_client_appsecret', //小程序 app_secret
        ];
        $wx_configs       = Model_Sysconfig::get_configs(0, $config_params);
        $this->app_id     = $wx_configs['cfg_global_client_appkey'] ?? '';
        $this->app_secret = $wx_configs['cfg_global_client_appsecret'] ?? '';
    }

    /**
     * 自定义小程序配置
     * @param $config
     * @return $this
     */
    public function set_config($config = array())
    {
        if (isset($config['app_id'])) {
            $this->app_id = $config['app_id'];
        }
        if (isset($config['app_secret'])) {
            $this->app_secret = $config['app_secret'];
        }
        if (isset($config['mch_id'])) {
            $this->mch_id = $config['mch_id'];
        }
        if (isset($config['cert_path'])) {
            $this->cert_path = $config['cert_path'];
        }
        if (isset($config['key_path'])) {
            $this->key_path = $config['key_path'];
        }

        return $this;
    }

    /**
     * 初始化服务端
     * @return $this
     */
    public function get_client()
    {
        $this->access_token = $this->get_access_token();
        return $this;
    }

    /**
     * 获取access_token
     * @return bool|mixed
     */
    public function get_access_token()
    {
        // 从缓存获取
        $access_token_key = 'mini_app_service_access_token';
        $access_token     = self::cache('get', $access_token_key);
        if ($access_token) {
            return $access_token;
        }

        $res = $this->get(
            $this->token_url,
            array(
                'grant_type' => 'client_credential',
                'appid' => $this->app_id,
                'secret' => $this->app_secret
            )
        );

        if (isset($res['access_token'])) {
            self::cache('set', $access_token_key, $res['access_token']);
            return $res['access_token'];
        } else {
            return false;
        }
    }

    /**
     * 缓存设置与获取
     * @param $type
     * @param $key
     * @param $value
     * @param $expire_time
     * @return bool|mixed|void
     * @throws Cache_Exception
     */
    public function cache($type, $key, $value = '', $expire_time = 3600)
    {
        $cache_dir = CACHE_DIR . 'v5/html';
        if (!file_exists($cache_dir)) {
            mkdir($cache_dir, 0777, true);
        }
        $cache = Cache::instance('default');
        if ($type == 'get') {
            //获取缓存
            return $cache->get($key, '');
        } else if ($type == 'set') {
            //设置缓存
            return $cache->set($key, $value, $expire_time);
        }
    }

    /**
     * 获取当前微信小程序配置
     * @return array
     */
    public function get_config(): array
    {
        return array(
            'app_id' => $this->app_id,
            'app_secret' => $this->app_secret,
            'mch_id' => $this->mch_id,
            'cert_path' => $this->cert_path,
            'key_path' => $this->key_path
        );
    }

    /**
     * 发起post请求
     * @param $path
     * @param $options
     * @return array|mixed
     * @throws Kohana_Exception
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function post($path, $options = array())
    {
        $path          = $path . '?access_token=' . $this->access_token;
        $this->path    = $path;
        $this->options = $options;
        $url           = $this->domain . $path;

        $client   = new GuzzleHttp\Client();
        $response = $client->request('POST', $url, $options);
        return $this->response($response);
    }

    /**
     * @param $path
     * @param $options
     * @return array|mixed
     * @throws Kohana_Exception
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function get($path, $options = array())
    {
        $this->options = $options;
        $this->path    = $path;
        $url           = $this->domain . $this->path;

        $client   = new GuzzleHttp\Client();
        $response = $client->request('GET', $url, [
            'query' => $options
        ]);
        return $this->response($response);
    }

    /**
     * 处理请求返回结果
     * @param $response
     * @return array|mixed
     * @throws Kohana_Exception
     */
    public function response($response)
    {
        $code               = $response->getStatusCode(); // 200
        $reason             = $response->getReasonPhrase(); // OK
        $this->request_code = $code;
        $this->error_code   = -1;
        $result             = array();
        if ($code != 200) {
            $this->error_message = $reason;
        } else {
            $body   = $response->getBody();
            $result = json_decode($body, true);
            if ($result && is_array($result)) {
                $this->error_code    = $result['errcode'];
                $this->error_message = $result['errmsg'];
            }
        }

        $this->content = $result;

        // 日志
        $this->write_log();

        return $result;
    }

    /**
     * 记录日志
     * @return void
     * @throws Kohana_Exception
     */
    public function write_log()
    {
        // 日志
        $env_version = Kohana::$config->load('tools.miniappservice.debug');
        if ($env_version == 'develop') {
            $options = $this->options;
            if (isset($options['appid'])) {
                unset($options['appid']);
            }
            if (isset($options['secret'])) {
                unset($options['secret']);
            }
            $log = array(
                'path' => $this->path,
                'params' => $options,
                'response' => $this->content
            );
            St_Log::write('微信小程序接口请求', $log, 'miniapp/api/log');
        }
    }

    /**
     * 业务-是否失败
     * @return bool
     */
    public function is_failed()
    {
        return $this->request_code != 200 || $this->error_code != 0;
    }

    /**
     * 业务-是否成功
     * @return bool
     */
    public function is_successful()
    {
        return $this->request_code == 200 && $this->error_code == 0;
    }

    /**
     * 获取返回内容
     * @return mixed
     */
    public function get_content()
    {
        return $this->content;
    }

    /**
     * 获取错误内容
     * @return string
     */
    public function get_error_message()
    {
        return $this->error_message;
    }

    /**
     * 获取错误编码
     * @return null
     */
    public function get_error_code()
    {
        return $this->error_code;
    }
}